package org.example.reference;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

/**
 * -verbose:gc JVM会在控制台打印出垃圾回收的详细信息
 * -Xmx16m 设置 JVM 最大堆内存大小
 * -Xms16m 设置 JVM 初始堆内存大小
 */
public class SoftReferenceAndQueueDemo {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) {
        ReferenceQueue<BigObject> rq = new ReferenceQueue<>();
        //软引用所引用的对象占10MB，总的JVM内存设置为16MB
        SoftReference<BigObject> sr = new SoftReference<>(new BigObject(10 * _1MB), rq);

        System.out.println("Soft reference created, waiting for GC...");

        // 模拟内存压力，再创建10MB的空间，由于总空间为16MB，内存不足会触发GC
        createMemoryPressure();
        System.out.println("完成10MB空间的分配");

        // 检查软引用是否已经被垃圾回收
        if (sr.get() == null) {
            System.out.println("The BigObject has been garbage collected.");
        } else {
            System.out.println("The BigObject is still alive.");
        }

        //从引用队列中获取软引用，判断其指向的内存看空间是否被回收
        Reference reference=rq.poll();
        if(null!=reference && null==reference.get()){
            System.out.println("从引用队列中获取JVM回收的软引用对象，其中软引用对象指向的内存空间已被回收！");
        }

        // 等待引用队列中的事件，可以单独启动一个线程，用于监听队列中是否放入了回收的软引用，从而执行其他逻辑
        /*while (rq.poll() == null) {
            Thread.yield(); // 让出CPU以加速GC
        }*/
    }

    static void createMemoryPressure() {
        byte[] b = new byte[10 * _1MB];
        b = null; // 释放这个数组，以便让JVM认为有足够的内存去尝试回收soft reference
    }

    static class BigObject {
        byte[] bytes;

        BigObject(int size) {
            this.bytes = new byte[size];
        }
    }
}